﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using VerticalSpider.IDaos;
using VerticalSpider.XmlFileDaos.Exceptions;

namespace VerticalSpider.XmlFileDaos
{
    public class BaseXmlFileRepository<T> : IBaseRepository<T>
        where T : class
    {
        public readonly string RootPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, typeof(T).FullName);

        public void Add(string id, T model)
        {
            var filePath = GetFileFullPath(GetFileName(id));
            if (File.Exists(filePath))
                throw new FileAlreadyExistsException(filePath);

            using (var fs = new FileStream(filePath, FileMode.Create))
            {
                WriteModel(model, fs);
            }
        }

        public void Delete(string id)
        {
            var filePath = GetFileFullPath(GetFileName(id));
            if (File.Exists(filePath) == false)
                throw new FileNotFoundException(filePath);

            File.Delete(filePath);
        }

        public T Get(string id)
        {
            var filePath = GetFileFullPath(GetFileName(id));
            if (File.Exists(filePath) == false)
                throw new FileNotFoundException(filePath);

            using (var fs = new FileStream(filePath, FileMode.Open))
            {
                return ReadModel(fs);
            }
        }

        public IEnumerable<string> GetAllIds()
        {
            var files = Directory.GetFiles(RootPath, "*.xml");
            return files.Select(n => Path.GetFileNameWithoutExtension(n)).ToList();
        }

        public void Update(string id, T model)
        {
            var filePath = GetFileFullPath(GetFileName(id));
            if (File.Exists(filePath) == false)
                throw new FileNotFoundException(filePath);

            using (var fs = new FileStream(filePath, FileMode.Create))
            {
                fs.SetLength(0);

                WriteModel(model, fs);
            }
        }

        private string GetFileName(string id)
        {
            if (string.IsNullOrEmpty(id))
                throw new FileNotFoundException("empty id");

            return id + ".xml";
        }

        private string GetFileFullPath(string fileName)
        {
            return Path.Combine(RootPath, fileName);
        }

        public T ReadModel(Stream stream)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            return (T)serializer.Deserialize(stream);
        }

        public void WriteModel(T model, Stream stream)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            serializer.Serialize(stream, model);
        }
    }
}
